sign: API changes for public keys and CLI keys format
authorDenis Pynkin <denis.pynkin@collabora.com>
Fri, 9 Aug 2019 19:07:57 +0000 (22:07 +0300)
committerDenis Pynkin <denis.pynkin@collabora.com>
Wed, 25 Mar 2020 12:23:54 +0000 (15:23 +0300)
API changes:
- added function `ostree_sign_add_pk()` for multiple public keys using.
- `ostree_sign_set_pk()` now substitutes all previously added keys.
- added function `ostree_sign_load_pk()` allowed to load keys from file.
- `ostree_sign_ed25519_load_pk()` able to load the raw keys list from file.
- use base64 encoded public and private ed25519 keys for CLI and keys file.

Signed-off-by: Denis Pynkin <denis.pynkin@collabora.com>
apidoc/ostree-sections.txt
src/libostree/libostree-devel.sym
src/libostree/ostree-repo-pull.c
src/libostree/ostree-sign-dummy.h
src/libostree/ostree-sign-ed25519.c
src/libostree/ostree-sign-ed25519.h
src/libostree/ostree-sign.c
src/libostree/ostree-sign.h
src/ostree/ot-builtin-commit.c
src/ostree/ot-builtin-sign.c
tests/test-signed-commit.sh

index cfc4a3406b19fd3f121bb478c2cacde8f2ea8c25..806bd1a77664e8bf09567e8a566d6aeb43293b49 100644 (file)
@@ -719,6 +719,7 @@ ostree_sign_get_by_name
 ostree_sign_get_name
 ostree_sign_detached_metadata_append
 ostree_sign_metadata_verify
+ostree_sign_add_pk
 ostree_sign_load_pk
 ostree_sign_set_pk
 ostree_sign_set_sk
index 4066f383910b25ed7275e363463d39b2c8d2a66b..8be5a3bf8f78f8fd5c9c65c3280eed8a746f08b8 100644 (file)
@@ -33,6 +33,7 @@ global:
   ostree_sign_metadata_verify;
   ostree_sign_load_pk;
   ostree_sign_set_pk;
+  ostree_sign_add_pk;
   ostree_sign_set_sk;
   ostree_sign_dummy_get_type;
   ostree_sign_ed25519_get_type;
index 507bcc2e76057e38a2fde80cea97f1d3333d4a8c..781c2458303507ea6c4b3bf8428eee5b588c4b0a 100644 (file)
@@ -1508,13 +1508,21 @@ ostree_verify_unwritten_commit (OtPullData                 *pull_data,
       gboolean ret = FALSE;
       g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes (commit);
       /* list all signature types in detached metadata and check if signed by any? */
-      GStrv names = ostree_sign_list_names();
+      g_auto(GStrv) names = ostree_sign_list_names();
       for (guint i=0; i < g_strv_length (names); i++)
         {
-          g_autoptr (OstreeSign) sign = ostree_sign_get_by_name (names[i], error);
+          g_autoptr (OstreeSign) sign = NULL;
           g_autoptr(GVariant) signatures = NULL;
-          g_autofree gchar *signature_key = ostree_sign_metadata_key (sign);
-          g_autofree GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format (sign);
+          g_autofree gchar *signature_key = NULL;
+          g_autofree GVariantType *signature_format = NULL;
+
+          if ((sign = ostree_sign_get_by_name (names[i], error)) == NULL)
+          {
+              g_error_free (*error);
+              continue;
+          }
+          signature_key = ostree_sign_metadata_key (sign);
+          signature_format = (GVariantType *) ostree_sign_metadata_format (sign);
 
           signatures = g_variant_lookup_value (detached_metadata,
                                                signature_key,
@@ -1531,7 +1539,6 @@ ostree_verify_unwritten_commit (OtPullData                 *pull_data,
                                           ))
             ret = TRUE;
         }
-      g_strfreev(names);
       return ret;
     }
 
index 8bbd407dac026d10aa40ada538dc8419b6776b97..73bad135676b0051adc8db730603757078710e5b 100644 (file)
@@ -57,7 +57,5 @@ gboolean ostree_sign_dummy_metadata_verify (OstreeSign *self,
 
 gboolean ostree_sign_dummy_set_signature (OstreeSign *self, GVariant *key, GError **error);
 
-void ostree_sign_dummy_finalize (GObject *gobject);
-
 G_END_DECLS
 
index 6a110104ddb6c08a3b8cd5c50dafa5167dfe20ad..779c0b274dd0ce2a87d70273abeea06e976cb0d0 100644 (file)
 #include <sodium.h>
 #endif
 
+#define G_LOG_DOMAIN "OSTreeSign"
+
 #define OSTREE_SIGN_ED25519_NAME "ed25519"
 
 #define OSTREE_SIGN_METADATA_ED25519_KEY "ostree.sign.ed25519"
 #define OSTREE_SIGN_METADATA_ED25519_TYPE "aay"
 
+#if 0
+#define SIGNIFY_COMMENT_HEADER "untrusted comment:"
+#define SIGNIFY_ID_LENGTH 8
+#define SIGNIFY_MAGIC_ED25519 "Ed"
+#endif
+
 struct _OstreeSignEd25519
 {
   GObject parent;
   gboolean initialized;
   guchar *secret_key;
-  guchar *public_key;
+  GList *public_keys;
 };
 
 static void
@@ -61,12 +69,32 @@ ostree_sign_ed25519_iface_init (OstreeSignInterface *self)
   self->metadata_verify = ostree_sign_ed25519_metadata_verify;
   self->set_sk = ostree_sign_ed25519_set_sk;
   self->set_pk = ostree_sign_ed25519_set_pk;
+  self->add_pk = ostree_sign_ed25519_add_pk;
+  self->load_pk = ostree_sign_ed25519_load_pk;
+}
+
+static void
+ostree_sign_ed25519_finalize (GObject *object)
+{
+  g_debug ("%s enter", __FUNCTION__);
+#if 0
+  OstreeSignEd25519 *self = OSTREE_SIGN_ED25519 (object);
+
+  if (self->public_keys != NULL)
+    g_list_free_full (self->public_keys, g_object_unref);
+  if (self->secret_key != NULL)
+    free(self->secret_key);
+#endif
+  G_OBJECT_CLASS (ostree_sign_ed25519_parent_class)->finalize (object);
 }
 
 static void
 ostree_sign_ed25519_class_init (OstreeSignEd25519Class *self)
 {
   g_debug ("%s enter", __FUNCTION__);
+  GObjectClass *object_class = G_OBJECT_CLASS (self);
+
+  object_class->finalize = ostree_sign_ed25519_finalize;
 }
 
 static void
@@ -76,7 +104,7 @@ ostree_sign_ed25519_init (OstreeSignEd25519 *self)
 
   self->initialized = TRUE;
   self->secret_key = NULL;
-  self->public_key = NULL;
+  self->public_keys = NULL;
 
 #ifdef HAVE_LIBSODIUM
   if (sodium_init() < 0)
@@ -188,7 +216,7 @@ gboolean ostree_sign_ed25519_metadata_verify (OstreeSign *self,
       goto err;
     }
 
-  if ((sign->initialized != TRUE) || (sign->public_key == NULL))
+  if ((sign->initialized != TRUE) || (sign->public_keys == NULL))
     {
       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                           "Not able to verify: libsodium library isn't initialized properly");
@@ -207,20 +235,26 @@ gboolean ostree_sign_ed25519_metadata_verify (OstreeSign *self,
 
       g_debug("Read signature %d: %s", (gint)i, g_variant_print(child, TRUE));
 
-      if (crypto_sign_verify_detached ((guchar *) g_variant_get_data (child),
-                                       g_bytes_get_data (data, NULL),
-                                       g_bytes_get_size (data),
-                                       sign->public_key) != 0)
+      for (GList *public_key = sign->public_keys;
+           public_key != NULL;
+           public_key = public_key->next)
         {
-          /* Incorrect signature! */
-          g_debug("Signature couldn't be verified with key '%s'", 
-                  sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, sign->public_key, crypto_sign_PUBLICKEYBYTES));
-        }
-      else
-        {
-          ret = TRUE;
-          g_debug ("Signature verified successfully with key '%s'",
-                   sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, sign->public_key, crypto_sign_PUBLICKEYBYTES));
+          if (crypto_sign_verify_detached ((guchar *) g_variant_get_data (child),
+                                           g_bytes_get_data (data, NULL),
+                                           g_bytes_get_size (data),
+                                           public_key->data) != 0)
+            {
+              /* Incorrect signature! */
+              g_debug("Signature couldn't be verified with key '%s'",
+                      sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES));
+            }
+          else
+            {
+              ret = TRUE;
+              g_debug ("Signature verified successfully with key '%s'",
+                       sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, public_key->data, crypto_sign_PUBLICKEYBYTES));
+              break;
+            }
         }
     }
 
@@ -297,7 +331,7 @@ gboolean ostree_sign_ed25519_set_sk (OstreeSign *self,
     }
 
   hex = g_malloc0 (crypto_sign_SECRETKEYBYTES*2 + 1);
-  g_debug ("Set ed25519 secret key = %s", sodium_bin2hex (hex, crypto_sign_SECRETKEYBYTES*2+1, sign->secret_key, n_elements));
+//  g_debug ("Set ed25519 secret key = %s", sodium_bin2hex (hex, crypto_sign_SECRETKEYBYTES*2+1, sign->secret_key, n_elements));
 
   return TRUE;
 
@@ -313,16 +347,35 @@ gboolean ostree_sign_ed25519_set_pk (OstreeSign *self,
   g_debug ("%s enter", __FUNCTION__);
   g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE);
 
+  OstreeSignEd25519 *sign = ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self));
+
+  /* Substitute the key(s) with a new one */
+  if (sign->public_keys != NULL)
+    {
+      g_list_free_full (sign->public_keys, g_object_unref);
+      sign->public_keys = NULL;
+    }
+
+  return ostree_sign_ed25519_add_pk (self, public_key, error);
+}
+
+gboolean ostree_sign_ed25519_add_pk (OstreeSign *self,
+                                     GVariant *public_key,
+                                     GError **error)
+{
+  g_debug ("%s enter", __FUNCTION__);
+  g_return_val_if_fail (OSTREE_IS_SIGN (self), FALSE);
+
 #ifdef HAVE_LIBSODIUM
   OstreeSignEd25519 *sign = ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self));
   g_autofree char * hex = NULL;
+  gpointer key = NULL; 
 
   gsize n_elements = 0;
-  g_free (sign->public_key);
-  sign->public_key = (guchar *) g_variant_get_fixed_array (public_key, &n_elements, sizeof(guchar));
+  key = (gpointer) g_variant_get_fixed_array (public_key, &n_elements, sizeof(guchar));
 
   hex = g_malloc0 (crypto_sign_PUBLICKEYBYTES*2 + 1);
-  g_debug ("Read ed25519 public key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, sign->public_key, n_elements));
+  g_debug ("Read ed25519 public key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, key, n_elements));
 
   if (n_elements != crypto_sign_PUBLICKEYBYTES)
     {
@@ -331,7 +384,9 @@ gboolean ostree_sign_ed25519_set_pk (OstreeSign *self,
       goto err;
     }
 
-  g_debug ("Set ed25519 public key = %s", sodium_bin2hex (hex, crypto_sign_PUBLICKEYBYTES*2+1, sign->public_key, n_elements));
+  key = g_memdup (key, n_elements);
+  if (g_list_find (sign->public_keys, key) == NULL)
+      sign->public_keys = g_list_prepend (sign->public_keys, key);
 
   return TRUE;
 
@@ -339,3 +394,144 @@ err:
 #endif /* HAVE_LIBSODIUM */
   return FALSE;
 }
+
+
+static gboolean
+load_pk_from_stream (OstreeSign *self, GDataInputStream *key_data_in, GError **error)
+{
+  g_return_val_if_fail (key_data_in, FALSE);
+#ifdef HAVE_LIBSODIUM
+  gboolean ret = FALSE;
+
+#if 0
+/* Try to load the public key in signify format from the stream
+ * https://www.openbsd.org/papers/bsdcan-signify.html
+ * 
+ * FIXME: Not sure if we need to support that format.
+ * */
+  g_autofree gchar * comment = NULL;
+  while (TRUE)
+    {
+      gsize len = 0;
+      g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error);
+      if (error)
+        goto err;
+
+      if (line)
+        {
+          g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                               "Signify format for ed25519 public key not found");
+          goto err;
+        }
+      
+      if (comment == NULL)
+        {
+          /* Scan for the comment first and compare with prefix&suffix */
+          if (g_str_has_prefix (line, SIGNIFY_COMMENT_HEADER) && g_str_has_suffix (line, "public key"))
+            /* Save comment without the prefix and blank space */
+            comment = g_strdup (line + strlen(SIGNIFY_COMMENT_HEADER) + 1);
+        }
+      else
+        {
+          /* Read the key itself */
+          /* base64 encoded key */
+          gsize keylen = 0;
+          g_autofree guchar *key = g_base64_decode (line, &keylen);
+
+          /* Malformed key */
+          if (keylen != SIGNIFY_ID_LENGTH ||
+              strncmp (line, SIGNIFY_MAGIC_ED25519, strlen(SIGNIFY_MAGIC_ED25519)) != 0)
+            continue;
+
+        }
+    }
+#endif /* 0 */
+
+  /* Use simple file format with just a list of base64 public keys per line */
+  while (TRUE)
+    {
+      gsize len = 0;
+      g_autofree char *line = g_data_input_stream_read_line (key_data_in, &len, NULL, error);
+      g_autoptr (GVariant) pk = NULL;
+
+      if (*error != NULL)
+        goto err;
+
+      if (line == NULL)
+          goto out;
+      
+      /* Read the key itself */
+      /* base64 encoded key */
+      gsize key_len = 0;
+      g_autofree guchar *key = g_base64_decode (line, &key_len);
+
+      pk = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, key, key_len, sizeof(guchar));
+      if (ostree_sign_ed25519_add_pk (self, pk, error))
+        {
+          ret = TRUE;
+          g_debug ("Added public key: %s", line);
+        }
+      else
+        g_debug ("Invalid public key: %s", line);
+    }
+
+out:
+  return ret;
+
+err:
+#endif /* HAVE_LIBSODIUM */
+  return FALSE;
+}
+
+gboolean
+ostree_sign_ed25519_load_pk (OstreeSign *self,
+                             GVariant *options,
+                             GError **error)
+{
+  g_debug ("%s enter", __FUNCTION__);
+
+  OstreeSignEd25519 *sign = ostree_sign_ed25519_get_instance_private(OSTREE_SIGN_ED25519(self));
+
+  g_autoptr (GFile) keyfile = NULL;
+  g_autoptr (GFileInputStream) key_stream_in = NULL;
+  g_autoptr (GDataInputStream) key_data_in = NULL;
+
+  const gchar *remote_name = NULL;
+  const gchar *filename = NULL;
+
+  /* Clear already loaded keys */
+  if (sign->public_keys != NULL)
+    {
+      g_list_free_full (sign->public_keys, g_object_unref);
+      sign->public_keys = NULL;
+    }
+
+  /* Check if the name of remote is provided */
+  if (! g_variant_lookup (options, "remote", "&s", &remote_name))
+    remote_name = OSTREE_SIGN_ALL_REMOTES;
+
+  /* Read filename or use will-known if not provided */
+  if (! g_variant_lookup (options, "filename", "&s", &filename))
+    {
+      // TODO: define well-known places and load file(s)
+      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                           "Please provide a filename to load");
+      goto err;
+    }
+
+  keyfile = g_file_new_for_path (filename);
+  key_stream_in = g_file_read (keyfile, NULL, error);
+  if (key_stream_in == NULL)
+    goto err;
+  key_data_in = g_data_input_stream_new (G_INPUT_STREAM(key_stream_in));
+  g_assert (key_data_in != NULL);
+
+  if (!load_pk_from_stream (self, key_data_in, error))
+    goto err;
+
+  return TRUE;
+err:
+  return FALSE;
+}
+
index d4a6b56d912abd7fa188ea285c94df1aa614f40d..797ac138093f2b91c94537e9fbf1eabffc8406c9 100644 (file)
@@ -63,7 +63,13 @@ gboolean ostree_sign_ed25519_set_pk (OstreeSign *self,
                                      GVariant *public_key,
                                      GError **error);
 
-void ostree_sign_ed25519_finalize (GObject *gobject);
+gboolean ostree_sign_ed25519_add_pk (OstreeSign *self,
+                                     GVariant *public_key,
+                                     GError **error);
+
+gboolean ostree_sign_ed25519_load_pk (OstreeSign *self,
+                                      GVariant *options,
+                                      GError **error);
 
 _OSTREE_PUBLIC
 gboolean ostree_sign_ed25519_keypair_generate (OstreeSign *self,
@@ -71,5 +77,6 @@ gboolean ostree_sign_ed25519_keypair_generate (OstreeSign *self,
                                                GVariant **out_public_key,
                                                GError **error);
 
+
 G_END_DECLS
 
index 96455f86ece98c2822088b46f2edc8c4e48c0dac..0708395ca0e7551134a91e694fde88b7f675f5a3 100644 (file)
@@ -88,22 +88,31 @@ gboolean ostree_sign_set_pk (OstreeSign *self,
   return OSTREE_SIGN_GET_IFACE (self)->set_pk (self, public_key, error);
 }
 
+gboolean ostree_sign_add_pk (OstreeSign *self,
+                             GVariant *public_key,
+                             GError **error)
+{
+  g_debug ("%s enter", __FUNCTION__);
+
+  if (OSTREE_SIGN_GET_IFACE (self)->add_pk == NULL)
+    return TRUE;
+
+  return OSTREE_SIGN_GET_IFACE (self)->add_pk (self, public_key, error);
+}
+
 /* Load private keys for verification from anywhere.
  * No need to have the same function for secret keys -- the signing SW must do it in it's own way
  * */
 gboolean
 ostree_sign_load_pk (OstreeSign *self,
-                     gchar *remote_name,
+                     GVariant *options,
                      GError **error)
 {
   g_debug ("%s enter", __FUNCTION__);
 
   g_return_val_if_fail (OSTREE_SIGN_GET_IFACE (self)->load_pk != NULL, FALSE);
 
-  if (remote_name == NULL)
-    remote_name = OSTREE_SIGN_ALL_REMOTES;
-
-  return OSTREE_SIGN_GET_IFACE (self)->load_pk (self, remote_name, error);
+  return OSTREE_SIGN_GET_IFACE (self)->load_pk (self, options, error);
 }
 
 gboolean ostree_sign_data (OstreeSign *self,
index f06206aacc510e72b5b1b48585dc889446a7f773..78e2487d4f389b3bd02e288a1eb0b22fca5b14fa 100644 (file)
@@ -68,8 +68,12 @@ struct _OstreeSignInterface
                        GVariant *public_key,
                        GError **error);
 
+  gboolean (* add_pk) (OstreeSign *self,
+                       GVariant *public_key,
+                       GError **error);
+
   gboolean (* load_pk) (OstreeSign *self,
-                        gchar *remote_name,
+                        GVariant *options,
                         GError **error);
 
 };
@@ -126,9 +130,14 @@ gboolean ostree_sign_set_pk (OstreeSign *self,
                              GVariant *public_key,
                              GError **error);
 
+_OSTREE_PUBLIC
+gboolean ostree_sign_add_pk (OstreeSign *self,
+                             GVariant *public_key,
+                             GError **error);
+
 _OSTREE_PUBLIC
 gboolean ostree_sign_load_pk (OstreeSign *self,
-                              gchar *remote_name,
+                              GVariant *options,
                               GError **error);
 
 
index 4bbde92ea9352e11973fed49a314676bfe5c26c4..89ada19eda506010ecfc04682fc5c6eabc0f07f4 100644 (file)
@@ -868,11 +868,10 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
               else if (!g_strcmp0 (ostree_sign_get_name (sign), "ed25519"))
                 {
                   gsize key_len = 0;
-                  key = g_malloc0 (crypto_sign_SECRETKEYBYTES);
-                  if (sodium_hex2bin (key, crypto_sign_SECRETKEYBYTES,
-                                 keyid, strlen (keyid),
-                                 NULL, &key_len, NULL) != 0)
-                    {
+                  g_autofree guchar *key = g_base64_decode (keyid, &key_len);
+
+                  if ( key_len != crypto_sign_SECRETKEYBYTES)
+                  {
                       g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                    "Invalid KEY '%s'", keyid);
 
index 8edd5490bb5237ef29eb7c9b22aa8f2a7aabc0a4..e36a50f1a0df64c427eb6f4c7e059b2153929f1d 100644 (file)
@@ -136,10 +136,9 @@ ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation,
           if (!g_strcmp0(ostree_sign_get_name(sign), "ed25519"))
             {
               gsize key_len = 0;
-              key = g_malloc0 (crypto_sign_PUBLICKEYBYTES);
-              if (sodium_hex2bin (key, crypto_sign_PUBLICKEYBYTES,
-                                  key_ids[ii], strlen (key_ids[ii]),
-                                  NULL, &key_len, NULL) != 0)
+              g_autofree guchar *key = g_base64_decode (key_ids[ii], &key_len);
+              
+              if ( key_len != crypto_sign_PUBLICKEYBYTES)
                 {
                   g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                "Invalid KEY '%s'", key_ids[ii]);
@@ -170,10 +169,9 @@ ostree_builtin_sign (int argc, char **argv, OstreeCommandInvocation *invocation,
           if (!g_strcmp0(ostree_sign_get_name(sign), "ed25519"))
             {
               gsize key_len = 0;
-              key = g_malloc0 (crypto_sign_SECRETKEYBYTES);
-              if (sodium_hex2bin (key, crypto_sign_SECRETKEYBYTES,
-                                  key_ids[ii], strlen (key_ids[ii]),
-                                  NULL, &key_len, NULL) != 0)
+              g_autofree guchar *key = g_base64_decode (key_ids[ii], &key_len);
+
+              if ( key_len != crypto_sign_SECRETKEYBYTES)
                 {
                   g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
                                "Invalid KEY '%s'", key_ids[ii]);
index 08993c60fae35587d2aef6fc610982afe45c8697..55945f8a20cccde4f920292801b08fd05d0551fc 100755 (executable)
@@ -60,16 +60,16 @@ openssl genpkey -algorithm ed25519 -outform PEM -out "${PEMFILE}"
 if has_libsodium; then
     # Based on: http://openssl.6102.n7.nabble.com/ed25519-key-generation-td73907.html
     # Extract the private and public parts from generated key.
-    PUBLIC="$(openssl pkey -outform DER -pubout -in ${PEMFILE} | hexdump -s 12 -e '16/1 "%.2x"')"
-    SEED="$(openssl pkey -outform DER -in ${PEMFILE} | hexdump -s 16 -e '16/1 "%.2x"')"
+    PUBLIC="$(openssl pkey -outform DER -pubout -in ${PEMFILE} | tail -c 32 | base64)"
+    SEED="$(openssl pkey -outform DER -in ${PEMFILE} | tail -c 32 | base64)"
     # Secret key is concantination of SEED and PUBLIC
-    SECRET="${SEED}${PUBLIC}"
+    SECRET="$(echo ${SEED}${PUBLIC} | base64 -d | base64 -w 0)"
 
     echo "SEED = $SEED"
     echo "PUBLIC = $PUBLIC"
 
     echo "Signed commit with ed25519: ${SECRET}" >> file.txt
-    ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s "Signed with ed25519 module" --sign=${SECRET} --sign-type=ed25519  
+    ${CMD_PREFIX} ostree --repo=${test_tmpdir}/repo commit -b main -s "Signed with ed25519 module" --sign="${SECRET}" --sign-type=ed25519
     COMMIT="$(ostree --repo=${test_tmpdir}/repo rev-parse main)"
 
     # Ensure that detached metadata contain signature